package org.shagin.jfin.data.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import org.shagin.jfin.core.Debug;
import org.shagin.jfin.core.CoreUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The Class OperationRule.
 */
public abstract class OperationRule extends AbstractBudgetItem {
    private static final Logger log = LoggerFactory
            .getLogger(OperationRule.class);

    private Account sourceAccount;
    private OperationCategoryLeaf category;
    private List<OperationRuleAction> actions = new ArrayList<OperationRuleAction>();

    /**
     * Instantiates a new operation rule.
     * 
     * @param ruleId the rule id
     * @param sourceAccount the source account
     * @param category the category
     * @param actions the actions
     */
    public OperationRule(String ruleId, Account sourceAccount,
            OperationCategoryLeaf category, List<OperationRuleAction> actions,
            IBudget budget) {
        super(ruleId);
        CoreUtils.checkNotNull(sourceAccount, "sourceAccount");
        CoreUtils.checkNotNull(category, "category");
        CoreUtils.checkNotNull(actions, "actions");
        CoreUtils.checkNotNull(budget, "budget");

        this.sourceAccount = sourceAccount;
        this.category = category;
        add(actions);
        category.addRule(this);
        this.budget = budget;

    }

    /**
     * Gets the category.
     * 
     * @return the category
     */
    public OperationCategory getCategory() {
        return category;
    }

    /**
     * Gets the roots.
     * 
     * @param rules the rules
     * @return the roots
     */
    public static List<OperationCategory> getRoots(List<OperationRule> rules) {
        Debug.traceEnter(log);
        List<OperationCategory> result = new ArrayList<OperationCategory>();
        for (OperationRule rule : rules) {
            OperationCategory category = rule.getCategory();
            if (null != category) {
                category = category.getRoot();
                if (!result.contains(category))
                    result.add(category);
            }
        }
        return result;
    }

    /**
     * Gets the source account.
     * 
     * @return the source account
     */
    public Account getSourceAccount() {
        return sourceAccount;
    }

    /**
     * Sets the source account.
     * 
     * @param account the new source account
     */
    public void setSourceAccount(Account account) {
        sourceAccount = account;
    }

    /**
     * Gets the actions.
     * 
     * @return the actions
     */
    public List<OperationRuleAction> getActions() {
        return Collections.unmodifiableList(actions);
    }

    /**
     * Adds the.
     * 
     * @param operationRuleAction the operation rule action
     * @return true, if successful
     */
    public boolean add(OperationRuleAction operationRuleAction) {
        operationRuleAction.setOperationRule(this);
        return actions.add(operationRuleAction);
    }

    /**
     * Adds the.
     * 
     * @param actions the actions
     */
    public void add(List<OperationRuleAction> actions) {
        for (OperationRuleAction operationRuleAction : actions) {
            add(operationRuleAction);
        }
    }

    /**
     * Removes the.
     * 
     * @param operationRuleAction the operation rule action
     * @return true, if successful
     */
    public boolean remove(OperationRuleAction operationRuleAction) {
        operationRuleAction.setOperationRule(null);
        return actions.remove(operationRuleAction);
    }

    @Override
    public String toString() {
        // TODO Localize
        StringBuilder sb = new StringBuilder();
        sb.append(getId()).append(" - [").append(sourceAccount.getId())
                .append("]");
        sb.append(" : ").append(toString(actions));
        return sb.toString();
    }

    public static String toString(List<OperationRuleAction> actions) {
        // TODO Localize
        StringBuilder sb = new StringBuilder();
        int i = 0;
        final int MAX = 2;
        for (Iterator<OperationRuleAction> iterator = actions.iterator(); iterator
                .hasNext();) {
            OperationRuleAction operationRuleAction = iterator.next();
            sb.append(operationRuleAction.toString());
            if (iterator.hasNext() && i < (MAX - 1))
                sb.append(", ");
            i++;
            if (i >= MAX) {
                if (iterator.hasNext())
                    sb.append(" +").append(actions.size() - MAX)
                            .append(" other");
                break;
            }
        }
        return sb.toString();
    }
}
